package netty.http;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;

import java.net.InetSocketAddress;

/**
 * \* User: Administrator
 * <p>
 * \* Date: 2020/10/28
 * <p>
 * \* Time: 10:24
 * <p>
 * Description:
 * 服务端启动过程：
 * 一、配置线程池
 * 二、Channel初始化
 * SO_KEEPALIVE : tcp连接保活
 * SO_BACKLOG：已完成三次握手的请求队列最大长度，高并发下适当调大
 * TCP_NODELAY：true标识tcp会将网络数据包累积到一定量才会发送，会造成一定的数据延迟，如果对数据传输延迟敏感，应该禁用该参数
 * SO_SNDBUF：tcp数据发送缓冲区大小
 * SO_RCVBUF：tcp数据接受缓冲区大小，tcp数据接受缓冲区大小
 * SO_LINGER：设置延迟关闭的时间，等待缓冲区中的数据发送完成
 * CONNECT_TIMEOUT_MILLIS：建立连接的超时时间
 * 三、端口绑定
 */
public class HttpServer {
    public void start(int port) throws InterruptedException {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup) //主从多线程模型
                    //NioServerSocketChannel 异步tcp服务端
                    //NioSocketChannel 异步tcp客户端
                    //OioSocketChannel 同步tcp客户端
                    //OioServerSocketChannel 同步tcp服务端
                    //NioDatagramChannel 异步udp连接
                    //OioDatagramChannel 同步udp连接
                    .channel(NioServerSocketChannel.class) //设置channel类型
                    .localAddress(new InetSocketAddress(port))
                    //注册ChannelHandler
                    //在Netty中可以通过ChannelPipeline去注册多个ChannelHandler。每个ChannelHandler各司其职，
                    //这样就可以实现最大化的代码复用，充分体现了Netty设计的优雅之处。
                    .childHandler(
                            new ChannelInitializer<SocketChannel>() {
                                @Override
                                protected void initChannel(SocketChannel socketChannel) throws Exception {
                                    socketChannel.pipeline()
                                            .addLast("codec", new HttpServerCodec()) //http编解码
                                            .addLast("compressor", new HttpContentCompressor()) //HttpContent压缩
                                            .addLast("aggregator", new HttpObjectAggregator(65536)) //http消息聚合
                                            .addLast("handler", new HttpServerHandler()); //自定义业务处理器
                                }
                            }).childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            channelFuture.channel().closeFuture().addListener((ChannelFutureListener) future -> System.out.println(future.channel().toString() + "链路关闭"));
            System.out.println("Http Server Started Listening on" + port);

            channelFuture.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new HttpServer().start(8099);
    }
}
